import json
import re
from collections import OrderedDict

from django.contrib.auth import login, logout
from django.db import DatabaseError
from django.http import HttpResponse
from django.http import HttpResponseForbidden
from django.shortcuts import render, redirect
from django_redis import get_redis_connection

from apps.goods.models import GoodsChannel, SKU
from apps.users.utils import generate_verify_email_url
from meiduo_mall.settings.dev import logger
from utils.response_code import RETCODE

# Create your views here.
from django import http
from django.urls import reverse
from django.views import View
from apps.users.models import User, Address
from django.contrib.auth.mixins import LoginRequiredMixin

class UsernameCOuntView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"OK",'count':count})

class MobileCOuntView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"OK",'count':count})

class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """
        提供注册界面
        :param request: 请求对象
        :return: 注册界面
        """
        # return HttpResponse("1234")
        return render(request, 'register.html')
    def post(self,request):
        #检验参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
    #校验参数
        # 判断参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        # 判断两次密码是否一致
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选用户协议')
        #判断短信验证码是否正确

           #接收短信验证码参数
        sms_code = request.POST.get('msg_code')
        redis_sms_client = get_redis_connection('sms_code')
        redis_sms_code = redis_sms_client.get('sms_%s'% mobile)

        if not redis_sms_code:
            return render(request,'register.html',{'sms_code_errmsg':"无效的短信验证码"})
        redis_sms_client.delete('sms_%s'% mobile)
        if sms_code != redis_sms_code.decode():
            return render(request,'register.html',{'sms_code_errmsg':"无效的短信验证"})
        try:
            #注册
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except DatabaseError:
            return render(request, 'register.html', {'register_errmsg': '注册失败'})

        # 实现状态保持
        login(request, user)
        #重定向
        return redirect(reverse('contents:index'))
    
class LoginView(View):
    def get(self,request):
        return render(request,'login.html')
    def post(self,request):
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')
        #用户判断
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return HttpResponseForbidden('请输入5-20个字符的用户名')
            # 2.2 密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseForbidden('请输入8-20位的密码')
        #django自带的认证系统
        from django.contrib.auth import authenticate, login
        user = authenticate(request,username=username, password=password)
        #判空
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})

        # 4.保持登录状态
        login(request, user)

        # 5.是否记住用户名
        if remembered != 'on':
            # 不记住用户名, 浏览器结束会话就过期
            request.session.set_expiry(0)
        else:
            # 记住用户名, 浏览器会话保持两周
            request.session.set_expiry(None)
        #操作 next
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))
        # response = redirect(reverse('contents:index'))
        #存用户名到cookie里面去
        response.set_cookie("username",user.username,max_age=2*14*24*3600)

        #登陆成功，合并购物车
        from apps.carts.utils import merge_cart_cookie_to_redis
        merge_cart_cookie_to_redis(request,response)


        # 6.返回响应结果
        return response

class LogoutView(View):
    def get(self,request):
        from django.contrib.auth import logout
        logout(request)

        response = redirect(reverse('contents:index'))
        response.delete_cookie('username')

        return response

class UserInfoView(LoginRequiredMixin,View):
    def get(self,request):
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request,'user_center_info.html',context)

class EmailView(LoginRequiredMixin,View):
    def put(self,request):
        #接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')
        #解析参数
        # if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
        #     return http.HttpResponseForbidden('参数email有误')
        #修改数据 email
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            # 返回响应对象
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})
        #发邮件
        verify_url = generate_verify_email_url(request.user)
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(email,verify_url)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})

class EmailVerifyView(View):
    def get(selfself,request):
        # 1.接收参数  request.GET
        # user_id = request.GET.get('user_id')
        # email = request.GET.get('email')
        #通过token的值进行获取
        token = request.GET.get('token')

        #解密：邮件信息的返回到后端的信息
        from utils.secret import SecretOauth
        data_dict = SecretOauth().loads(token)
        user_id = data_dict.get('user_id')
        email = data_dict.get('email')
        # 2.校验
        try:
            user = User.objects.get(id=user_id, email=email)
        except Exception as e:
            print(e)
            return http.HttpResponseForbidden('token无效的!')

        # 3. 修改 email_active
        user.email_active = True
        user.save()

        # 4. 返回
        return redirect(reverse('users:info'))

# 9. 展示收货地址
class AddressView(LoginRequiredMixin, View):
    def get(self, request):
        # 1.根据用户 查询所有地址  filter()
        addresses = Address.objects.filter(user=request.user, is_deleted=False)

        # 2.转换前端的数据格式
        adressess_list = []
        for address in addresses:
            adressess_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })

        context = {
            'default_address_id': request.user.default_address_id,
            'addresses': adressess_list,
        }

        return render(request, 'user_center_site.html', context)
#增加收货地址
class AddressAddView(LoginRequiredMixin, View):
    def post(self, request):

        # 限制增加个数 不能超过20个
        count = Address.objects.filter(user=request.user,is_deleted=False).count()
        # count = request.user.addresses.filter(is_deleted=False).count()
        if count > 20:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})


        # 1. 接收参数 form, json
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2.校验 判空 正则:
        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')
        # 3. orm = create() save()  #保存地址信息
        #给address表创建用户创建地址时所需要的信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
            # 设置用户的默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':"新增地址失败"})

        # 4.数据转换—>dict
        address_dict = {
            "id": address.id,
            "title": address.title,

            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})

#修改、删除地址
class AddressDeleteView(LoginRequiredMixin,View):
    def put(self,request,address_id):
        json_dict = json.loads(request.body.decode())
        print(type(address_id),address_id)
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 2.校验 判空 正则:
        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')
        # 3. orm = create() save()  #保存地址信息
        # 给address表创建用户创建地址时所需要的信息
        # 给address表创建用户创建地址时所需要的信息
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
        except Exception as e:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': "更新地址失败"})

        # 4.数据转换—>dict
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})
    def delete(self,request,address_id):
        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted = True
            address.save()
        except:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'数据库删除失败'})
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"删除数据库成功"})
#设置默认地址
class AddressDefaultView(LoginRequiredMixin,View):
    def put(self,request,address_id):
        try:
            address = Address.objects.get(id=address_id)
            request.user.default_address = address
            request.user.save()
        except:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'默认地址失败'})
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"设置默认地址成功"})
#修改地址的标题
class AddressTitleView(LoginRequiredMixin,View):
    def put(self,request,address_id):
        title = json.loads(request.body.decode()).get('title')
        try:
            address = Address.objects.get(id=address_id)
            address.title = title
            address.save()
        except:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'修改标题失败失败'})
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"修改标题成功"})
#10修改密码
class ChangePwdView(View):
    def get(self,request):
        return render(request,'user_center_pass.html')
    def post(self,request):
        #1.接受参数
        old_password = request.POST.get("old_pwd")
        new_password = request.POST.get("new_pwd")
        new_password2 = request.POST.get("new_cpwd")
        #验证
        user = request.user
        #判断密码是否正确
        if not user.check_password(old_password):
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码错误'})
        #重新设置密码
        if new_password !=new_password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        try:
            user.set_password(new_password) #设置密码，但需要保存
            user.save()
        except:
            return render(request, 'user_center_pass.html', {'change_pwd_errmsg': '修改密码错误'})
        #重定向  新密码输入完成，需要重定向到首页
        response = redirect(reverse('users:login'))
        #退出登陆、去除掉cookie
        logout(request)
        #去掉cookie
        response.delete_cookie('username')
        return response

#11保存用户信息记录
class UserBrowserView(View):
    def post(self,request):
        #接收参数   json.loads()  字符串传化为字典
        sku_id = json.loads(request.body.decode())['sku_id']
    #校验参数
        try:
            sku = SKU.objects.get(id=sku_id)
        except:
            return http.HttpResponseForbidden("商品不存在")
    #连接 redis
        client = get_redis_connection('history')
        #为了好区分  用户id进行拼接
        redis_key = 'history_%s' % request.user.id

        p1 = client.pipeline()
    #去重
        p1.lrem(redis_key,0,sku_id)
        p1.lpush(redis_key,sku_id)
        # 截取部分数据
        p1.ltrim(redis_key,0,4)
        p1.execute()
    #存储 覆盖信息
    #返回响应数据
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
    def get(self,request):
        client = get_redis_connection('history')   #存入redis的5号库
        sku_ids = client.lrange('history_%s' % request.user.id, 0, -1)

        # 3.通过 sku_ids --skus
        # skus = SKU.objects.filter(id__in=sku_ids) #通过id得到对应的数据，遍历数据
        # for sku in skus:
        skus_list = []
        for sku_id in sku_ids:
            #每遍历一次 取出对应的sku_id 然后根据id 得到sku数据
            sku = SKU.objects.get(id=sku_id)
            skus_list.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url

            })

        # 4.skus-->前端的数据格式--[{}]

        # 5.返回响应对象
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus_list})
